import React, { useState, useEffect, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Form, Input, Modal, Spin, Select, Space, Flex, Popover, message, Dropdown, Radio, Switch, Checkbox } from 'antd';
import type { MenuProps } from 'antd';
import Image from 'next/image';
import Icon, { PlusOutlined, DeleteOutlined, MinusOutlined, UpOutlined, DownOutlined, DashOutlined, EditOutlined } from '@ant-design/icons';
import useModal from './hooks/useModal';
import NodeModal from './nodeModal';
import { dataTypeEnum, DimensionMeasurementEnum, getMetricsOptionsChange, sqlTypesObj } from '@/components/workbenches/hooks/type';
import WorkbenchesIcon from '@/components/workbenches/icons';
import MyEmpty from '@/components/common/MyEmpty';
import { useRequest } from 'ahooks';
import './canvas-node.css'
import { cloneDeep } from 'lodash';

import { getList, getTablesByDatasourceId, getColumnsByTableId, sqlMetaData } from '@/client/api/workbenches';
interface dataListType { field: string; name: string; metrics: string, dataType: dataTypeEnum, isTimeDimension: boolean }
interface CustomNodeProps {
  graph: any;
  id: string;
  currentItem: any;
  setSaveStateChange: any;
  data: {
    dataList: Array<dataListType>;
    isMainTable: boolean;
    tableType: '' | '0' | '1';
    describe: string;
  };
  updateNodeData: (id: string, data: any) => void;
  removeNode: (id: string) => void;
  updateNodeStyle: (nodeInfo: { id: string, show: boolean }) => void;
  getNodeData: () => void;
  setCopilotVisible: (boolean: boolean) => void
}

const CustomNode: React.FC<CustomNodeProps> = ({ graph, currentItem, setSaveStateChange, id, data, updateNodeData, removeNode, updateNodeStyle, getNodeData, setCopilotVisible }) => {

  const { t, i18n } = useTranslation();
  // 添加本地状态
  const [localData, setLocalData] = useState(data.dataList);
  const [tableType, setTableType] = useState(data.tableType || '');
  const [describe, setDescribe] = useState('');
  const [nodeInfo, setNodeInfo] = useState({ id, show: true });
  const updataFieldChange = (ary: any[] = []) => {
    setLocalData(ary);
    // 通知全局状态更新
    updateNodeData(id, ary);
    getNodeData();
  }
  // 处理字段更新
  const handleFieldChange = (idx: number, field: string, value: string | number | boolean) => {
    const newData = [...localData];
    const data = { ...newData[idx], [field]: value };
    newData[idx] = data
    updataFieldChange(newData);
  };
  // 添加字段
  const handleAddField = (item: dataListType) => {
    const newData = [...localData, item];
    updataFieldChange(newData);
  };

  // 删除字段
  const handleRemoveField = (idx: number) => {
    const newData = localData.filter((_, i) => i !== idx);

    updataFieldChange(newData);
  };

  // let columnList = [
  //   { name: '地址', field: 'field1', metrics: DimensionMeasurementEnum.Dimension, dataType: dataTypeEnum.STRING },
  //   { name: '订单', field: 'field2', metrics: DimensionMeasurementEnum.Dimension, dataType: dataTypeEnum.STRING },
  //   { name: '订单时间', field: 'field3', metrics: DimensionMeasurementEnum.Dimension, dataType: dataTypeEnum.TIME },
  //   { name: '价格', field: 'field4', metrics: DimensionMeasurementEnum.Measurement, dataType: dataTypeEnum.NUMBER }
  // ]
  const [columnList, setColumnList] = useState<any[]>([])
  const items: MenuProps['items'] = [
    {
      key: '1',
      label: (
        <div onClick={() => removeNode?.(id)}>
          <DeleteOutlined className='mr-2' />
          删除
        </div>
      ),
    },
  ];

  const [describeOptions, setDescribeOptions] = useState<any[]>([
    // { label: 'order_id', value: 'order_id' },
    // { label: 'order_date', value: 'order_date' },
    // { label: 'order_amount', value: 'order_amount' },
    // { label: 'order_status', value: 'order_status' },
    // { label: 'order_customer_id', value: 'order_customer_id' },
  ]);
  const calculateTableOrSqlMap = () => {
    const nodes = graph.current.getNodes();
    const nodeDataList: any[] = nodes.map((node: any) => node.getData());
    let _tableOrSqlMap: any = {};
    nodeDataList.forEach((i) => {
      if (!_tableOrSqlMap[i.id]) {
        _tableOrSqlMap[i.id] = {
          id: i.id,
          describe: i.describe,
          tableType: i.tableType,
        };
      }
    });
    return _tableOrSqlMap;
  };
  const disabledChange = (item: any) => {
    const tableOrSqlMap = calculateTableOrSqlMap();
    let disabled = false;
    if (tableType == '0') {
      for (const key in tableOrSqlMap) {
        const i = tableOrSqlMap[key];
        if (i.tableType == 0 && i.describe == item.value && id != i.id) {
          disabled = true;
        }
      }
      return disabled;
    } else if (tableType == '1') {
      for (const key in tableOrSqlMap) {
        const i = tableOrSqlMap[key];
        if (i.tableType == 1 && i.describe == item.value && id != i.id) {
          disabled = true;
        }
      }
      return disabled;
    }
    return disabled;
  }
  const describeOptionsDisabledChange = (options: any[]) => {
    const newData = (options || []).map((item: any) => {
      if (tableType == '0') {
        return {
          ...item,
          disabled: disabledChange(item),
          label: item.tableName,
          value: item.tableName,
        };
      } else if (tableType == '1') {
        return {
          ...item,
          disabled: disabledChange(item),
          label: item.queryName,
          value: item.id
        };
      }
    })
    setDescribeOptions(newData);
    return newData;
  }
  const initData = async () => {
    if (!currentItem?.dataSourceId) return [];
    let res: any = {};
    if (tableType == '0') {
      res = await getTablesByDatasourceId({ datasourceId: currentItem.dataSourceId });
    } else if (tableType == '1') {
      res = await getList({ datasourceId: currentItem.dataSourceId });
    }
    const { code, data } = res.data || {};
    if (code == 0) {
      const newData = describeOptionsDisabledChange(data || []);

      return newData;
    }
    setDescribeOptions([]);
    return [];
  }
  useEffect(() => {
    initData();
  }, [tableType])
  useEffect(() => {
    const change = async () => {
      if (data.tableType && data.describe) {

        setTableType(data.tableType);
        graphSetDataChange({ key: 'tableType', value: data.tableType });
        const describeOptions = await initData();

        const dataInfo: any = describeOptions.find((item: any) => item.value == data.describe)
        setDescribe(data.describe);
        graphSetDataChange({ key: 'describe', value: data.describe });
        graphSetDataChange({ key: 'tableOrSqlOptionsCurrentInfo', value: dataInfo });

        let newData = [];
        if (tableType == '0') {
          const res = await getColumnsByTableId({ tableId: dataInfo?.tableId });
          const { code, data } = res.data || {};
          if (code == 0) {
            newData = (data || []).map((item: any) => {
              const obj = { ...item, name: item.columnComment, field: item.columnName, };
              if (sqlTypesObj.numberTypes.includes(item.columnType)) {
                obj.metrics = DimensionMeasurementEnum.Measurement;
                obj.dataType = dataTypeEnum.NUMBER;
                obj.columnPrecision = 2; //默认保留两位小数
              } else if (sqlTypesObj.stringTypes.includes(item.columnType)) {
                obj.metrics = DimensionMeasurementEnum.Dimension;
                obj.dataType = dataTypeEnum.STRING;
              } else if (sqlTypesObj.timeTypes.includes(item.columnType)) {
                obj.metrics = DimensionMeasurementEnum.Dimension;
                obj.dataType = dataTypeEnum.TIME;
                obj.isTimeDimension = false;//是否为时间维度
              }
              return obj;
            })
          }
        } else if (tableType == '1') {
          const params = {
            "datasourceId": currentItem.dataSourceId,
            "schemaName": currentItem.dataSourceData.name,
            "sql": dataInfo?.querySql
          }
          const res = await sqlMetaData(params);
          const { code, data } = res.data || {};
          if (code == 0) {
            newData = (data || []).map((item: any) => {
              const obj: any = { name: item, field: item, };
              obj.metrics = DimensionMeasurementEnum.Dimension;
              obj.dataType = dataTypeEnum.STRING;
              return obj;
            })
          }
        }
        setColumnList(newData);
        //设置表或sql字段字段，用于节点连线选择
        graphSetDataChange({ key: 'fieldList', value: newData });

      }
    }
    change();
  }, [data?.tableType, data?.describe])
  const edgeDataChange = () => {
    if (!graph.current) return
    const l_edges = graph.current.getConnectedEdges(id, { incoming: true, });//输入边
    const r_edges = graph.current.getConnectedEdges(id, { outgoing: true });//输出边
    if (l_edges?.length) {
      for (const edge of l_edges) {
        const data = { ...edge.getData() };
        for (const i of data.fields) {
          i.rField = '';
        }
        edge.setData({
          ...data,
        });
      }
    }
    if (r_edges?.length) {
      for (const edge of r_edges) {
        const data = { ...edge.getData() };
        for (const i of data.fields) {
          i.lField = '';
        }
        edge.setData({
          ...data,
        });
      }
    }
    // console.log('ta434343rget', graph.current.toJSON(), l_edges, r_edges, id)
  }
  const tableChange = async (value: string) => {
    const dataInfo: any = describeOptions.find((item: any) => item.value == value)
    setDescribe(value);
    graphSetDataChange({ key: 'describe', value });
    graphSetDataChange({ key: 'tableOrSqlOptionsCurrentInfo', value: dataInfo });

    updataFieldChange([]);
    let newData = [];
    if (tableType == '0') {
      const res = await getColumnsByTableId({ tableId: dataInfo?.tableId });
      const { code, data } = res.data || {};
      if (code == 0) {
        newData = (data || []).map((item: any) => {
          const obj = { ...item, name: item.columnComment, field: item.columnName, };
          if (sqlTypesObj.numberTypes.includes(item.columnType)) {
            obj.metrics = DimensionMeasurementEnum.Measurement;
            obj.dataType = dataTypeEnum.NUMBER;
            obj.columnPrecision = 2; //默认保留两位小数
          } else if (sqlTypesObj.stringTypes.includes(item.columnType)) {
            obj.metrics = DimensionMeasurementEnum.Dimension;
            obj.dataType = dataTypeEnum.STRING;
          } else if (sqlTypesObj.timeTypes.includes(item.columnType)) {
            obj.metrics = DimensionMeasurementEnum.Dimension;
            obj.dataType = dataTypeEnum.TIME;
            obj.isTimeDimension = false;//是否为时间维度
          }
          return obj;
        })
      }
    } else if (tableType == '1') {
      const params = {
        "datasourceId": currentItem.dataSourceId,
        "schemaName": currentItem.dataSourceData.name,
        "sql": dataInfo.querySql
      }
      const res = await sqlMetaData(params);
      const { code, data } = res.data || {};
      if (code == 0) {
        newData = (data || []).map((item: any) => {
          const obj: any = { name: item, field: item, };
          obj.metrics = DimensionMeasurementEnum.Dimension;
          obj.dataType = dataTypeEnum.STRING;
          return obj;
        })
      }
    }
    setColumnList(newData);
    //设置表或sql字段字段，用于节点连线选择
    graphSetDataChange({ key: 'fieldList', value: newData });

    // 调整连接字段
    edgeDataChange();

  }
  useEffect(() => {
    if (tableType != null && tableType != '' && describe != null && describe != ''

    ) {
      const obj = { id, describe: true, field: true }
      if (describeOptions?.length) {
        const ok = describeOptions.find(i => i.value == describe);
        if (!ok) {
          obj.describe = false;
        }
      } else {
        obj.describe = false;
      }

      if (columnList?.length) {
        const fieldAry = columnList.map(i => i.field);
        for (const i of localData) {
          if (!fieldAry.includes(i.field)) {
            obj.field = false;
          }
        }
      } else {
        obj.field = false;
      }
      setSaveStateChange(obj)

    }

  }, [tableType, describe, describeOptions, localData, columnList])
  const {
    open,
    form,
    setForm,
    setOpen,
    modalType,
    updataNodeModal
  } = useModal();
  const graphSetDataChange = ({ key, value }: any) => {
    const node = graph.current?.getCellById(id) as Node;
    if (node) {
      const oldData = node.getData() || {};

      const data = {
        ...oldData,
        [key]: value,
      };
      node.setData(cloneDeep(data),
        {
          overwrite: true,
          deep: true
        }
      );
    }
  }
  const getIconChange = (item: any, type: 'table' | 'model') => {
    if (type == 'model') {
      if ('isTimeDimension' in item && item.isTimeDimension) {
        return <WorkbenchesIcon type='模型指标_时间维度' styClass='!x' />
      }
      if (item.metrics == DimensionMeasurementEnum.Dimension) {
        return <WorkbenchesIcon type='模型指标_维度' styClass='!x' />
      }
      if (item.metrics == DimensionMeasurementEnum.Measurement) {
        return <WorkbenchesIcon type='模型指标_度量' styClass='!x' />
      }
    }
    if (type == 'table') {
      if (item.dataType == dataTypeEnum.TIME) {
        return <WorkbenchesIcon type='时间维度' styClass='!x' />
      }
      if (item.metrics == DimensionMeasurementEnum.Dimension) {
        return <WorkbenchesIcon type='维度' styClass='!x' />
      }
      if (item.metrics == DimensionMeasurementEnum.Measurement) {
        return <WorkbenchesIcon type='度量' styClass='!x' />
      }
    }
  }

  const describeOptionsRender = (opt: any) => {
    const l1 = tableType == '0' ? (opt?.tableName || '') : (opt?.queryName || '');
    const l2 = tableType == '0' ? (opt?.tableComment || '') : (opt?.querySql || '');
    return (
      <div className="flex justify-between items-center">
        <div className="whitespace-nowrap overflow-hidden text-ellipsis w-44" title={l1} >
          {l1}
        </div>
        <div className="whitespace-nowrap overflow-hidden text-ellipsis w-24 ml-4 text-[#6D7278]" title={l2} >
          {l2}
        </div>
      </div>
    )
  }
  return (
    <div className="workbenches-B620E0 canvas-node p-2 radius bg-white dark:bg-[#1b1d20] rounded-md" style={{ width: '100%', height: '100%' }}>
      <Flex className="node-header justify-between">
        <div className='flex items-center'>
          <div onClick={() => {
            const data = { ...nodeInfo, show: !nodeInfo.show }
            setNodeInfo(() => data);
            updateNodeStyle(data);

          }} className="cursor-pointer">
            {nodeInfo.show ? <UpOutlined /> : <DownOutlined />}
          </div>
          <Select
            className='w-14 ml-2'
            value={tableType}
            onChange={(value) => {
              setTableType(value);
              graphSetDataChange({ key: 'tableType', value });
              setDescribe('');
              setColumnList([]);
              updataFieldChange([]);
            }}
          >
            <Select.Option value="0" >
              <div className='flex items-center'>
                <WorkbenchesIcon type='表' styClass='!x' />
                {/* <div className='ml-2'> 数据</div> */}
              </div>
            </Select.Option>
            <Select.Option value="1">
              <div className='flex items-center'>
                <WorkbenchesIcon type='查询' styClass='!x' />
                {/* <div className='ml-2'> 查询</div> */}
              </div>
            </Select.Option>
          </Select>
          <Select
            className='w-72 ml-2'
            value={describe}
            options={describeOptions.map(opt => ({
              ...opt,
              label: describeOptionsRender(opt),
            }))}
            optionLabelProp="label"
            onChange={(value) => {
              tableChange(value);
            }}
            onMouseEnter={() => {
              describeOptionsDisabledChange(describeOptions)
            }}
            showSearch
            filterOption={(input, option) =>
              ((option?.tableName ?? '') as unknown as string)?.toLowerCase().includes(input.toLowerCase())
              ||
              ((option?.queryName ?? '') as unknown as string)?.toLowerCase().includes(input.toLowerCase())
            }
            placeholder={tableType == '1' ? '请选择数据' : '请选择查询'}
            optionRender={(option) => describeOptionsRender(option.data)}
          >
          </Select>
        </div>
        <div className='flex items-center'>
          <span className='cursor-pointer mr-2'
            onClick={() => setCopilotVisible(true)}>
            <WorkbenchesIcon type='agent' />
          </span>
          {
            !currentItem?.modelInfo?.status && <Dropdown menu={{ items }}>
            <DashOutlined className='cursor-pointer ml-2' />
           </Dropdown>
          }
          
        </div>
      </Flex>
      {
        nodeInfo.show && (
          <>
            <div className="mt-3 overflow-auto border-t border-borderColor dark:border-darkBorderColor pt-2" style={{ height: '150px' }}>
              {localData.map((item: any, idx) => (
                <Space key={idx} className={`field-item ${idx == localData.length ? '' : 'mt-1'} flex items-center justify-between`} wrap>
                  <div className='flex items-center'>
                    <div className='w-16 truncate' title={item.field} >
                      {item.field}
                    </div>
                    <Input
                      value={item.name}
                      maxLength={30}
                      onChange={(e) => {
                        handleFieldChange(idx, 'name', e.target.value)
                      }}
                      className={`w-32 ml-2 ${item.name ? '' : 'border-[red]'} border`}
                      prefix={getIconChange(item, 'model')}
                    />
                    <Radio.Group
                      value={item.metrics}
                      onChange={(e) => {
                        handleFieldChange(idx, 'metrics', e.target.value)
                      }} className='w-32 ml-4 dark:text-white workbenches-B620E0' options={getMetricsOptionsChange(item.dataType)}>
                    </Radio.Group>
                    {
                      dataTypeEnum.TIME == item.dataType &&
                      //   <>
                      //   <Switch className='ml-2' value={item.isTimeDimension} onChange={(value: boolean) => handleFieldChange(idx, 'isTimeDimension', value)} />
                      //   <span className='ml-2' >时间维度</span>
                      // </>
                      <Checkbox checked={item.isTimeDimension} className='w-24 ml-2 workbenches-B620E0' onChange={(e: any) => handleFieldChange(idx, 'isTimeDimension', e.target.checked)}>时间维度</Checkbox>
                    }
                  </div>

                  <div className='flex items-center'>
                    <EditOutlined className='cursor-pointer' onClick={() => updataNodeModal({ ...item, idx })} />
                    <MinusOutlined className='cursor-pointer mx-2' onClick={() => handleRemoveField(idx)} />
                  </div>
                </Space>
              ))}
              {
                !localData?.length && <MyEmpty description='请添加数据' />
              }

            </div>
            <div className='flex items-center justify-center'>
              <Popover
                placement='bottom'
                trigger='hover'
                title=''
                content={
                  <div className='w-max-52 max-h-96 overflow-y-scroll gap-1'>
                    {columnList.map((item, idx) => {
                      const fieldAry = localData.map(i => i.field);
                      const isClick = !fieldAry.includes(item.field);
                      return (
                        <Flex key={idx} className={`w-full cursor-${isClick ? 'pointer' : 'not-allowed'}`} wrap
                          onClick={() => isClick ? handleAddField(item) : null}>
                          <span>{getIconChange(item, 'table')}</span>
                          <span className={`ml-2 ${isClick ? '' : 'text-zinc-400'}`}>
                            {item.field?.length > 20 ? item.field?.substring(0, 20) + '...' : item.field}
                          </span>
                        </Flex>
                      )
                    })}
                  </div>
                }
              >
                <Button
                  type="text"
                  className='dark:text-white'
                  icon={<PlusOutlined />}
                >
                </Button>
              </Popover>
            </div>
          </>
        )
      }

      {open && <NodeModal
        open={open}
        form={form}
        columnList={columnList}
        onCancel={() => {
          setOpen(false);
        }}
        onOk={(e: any, index: number) => {
          setOpen(false);
          const newData = [...localData];
          newData[index] = { ...newData[index], ...e };
          updataFieldChange(newData);
        }}
        refresh={() => { }}
        type={modalType} />
      }
    </div>
  );
};

export default CustomNode;